#include "mainwindow.h"
#include "identifydialog.h"
#include "preferencesdialog.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent)
{
    labeled=0;
    loaded=0;
    scaleFactor = 1;
    erodeSize = 1;
    dilateSize = 1;
    threshold = 128;

    originalImage = new QImage();

    imageViewer = new ImageViewport(&labelManager);
    imageViewer->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
    imageViewer->setScaledContents(true);
    connect(&labelManager,SIGNAL(Updated()),this,SLOT(UpdateViewport()));
    connect(&labelManager,SIGNAL(Updated()),this,SLOT(UpdateStatusBar()));

    scrollArea = new QScrollArea();
    scrollArea->setBackgroundRole(QPalette::Dark);
    scrollArea->setWidget(imageViewer);
    setCentralWidget(scrollArea);

    CreateActions();
    CreateMenus();
    CreateToolBars();
    CreateStatusBar();

    connect(this,SIGNAL(Loaded(bool)),this,SLOT(EnableIdentify(bool)));
    connect(this,SIGNAL(Labeled(bool)),this,SLOT(EnableSave(bool)));

    setWindowTitle(tr("TID Cromos"));
    //resize(500, 400);
}

MainWindow::~MainWindow()
{

}

void MainWindow::CreateActions(){
    openImageAction = new QAction(tr("&Open Image"),this);
    openImageAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_O));
    connect(openImageAction,SIGNAL(triggered()),this,SLOT(OpenImage()));

    saveImageAction = new QAction(tr("&Save Image"),this);
    saveImageAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_S));
    saveImageAction->setEnabled(false);
    connect(saveImageAction,SIGNAL(triggered()),this,SLOT(SaveImageDialog()));

    identifyAction = new QAction(tr("&Identify"),this); // Posar shortcut
    identifyAction->setEnabled(false);
    connect(identifyAction,SIGNAL(triggered()),this,SLOT(Identify()));

    zoomInAction = new QAction(QIcon(":/icons/ZoomIn.png"),tr("Zoom In"), this);
    connect(zoomInAction,SIGNAL(triggered()),this,SLOT(ZoomIn()));

    zoomOutAction = new QAction(QIcon(":/icons/ZoomOut.png"),tr("Zoom Out"), this);
    connect(zoomOutAction,SIGNAL(triggered()),this,SLOT(ZoomOut()));

    //tagAction = new QAction(tr("Tag"), this);
    //connect(tagAction,SIGNAL(triggered()),this,SLOT(Tag()));

    removeLabelAction = new QAction(tr("Remove Label"), this);
    connect(removeLabelAction,SIGNAL(triggered()),&labelManager,SLOT(RemoveSelectedLabel()));

    quitAction = new QAction(tr("Quit"),this);
    quitAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Q));
    connect(quitAction,SIGNAL(triggered()),this,SLOT(close()));

    preferencesAction = new QAction(tr("Preferences"),this);
    connect(preferencesAction,SIGNAL(triggered()),
            this,SLOT(OpenPreferences()));

    instructionsAction = new QAction(tr("Instructions"),this);
    connect(instructionsAction,SIGNAL(triggered()),
            this,SLOT(OpenInstructions()));

}

void MainWindow::CreateMenus(){
    fileMenu = menuBar()->addMenu(tr("&File"));
    fileMenu->addAction(openImageAction);
    fileMenu->addAction(saveImageAction);
    fileMenu->addAction(quitAction);
    toolsMenu = menuBar()->addMenu(tr("&Tools"));
    toolsMenu->addAction(identifyAction);
    toolsMenu->addAction(removeLabelAction);
    toolsMenu->addAction(preferencesAction);
    helpMenu = menuBar()->addMenu(tr("&Help"));
    helpMenu->addAction(instructionsAction);


}


void MainWindow::CreateToolBars(){

    toolBar = this->addToolBar(tr("ToolBar"));
    toolBar->addAction(zoomOutAction);
    toolBar->addAction(zoomInAction);

    toolBar->addAction(identifyAction);
    //toolBar->addAction(tagAction);

    toolBar->addAction(removeLabelAction);

}

void MainWindow::CreateStatusBar(){


    statusBar()->showMessage("Ready",2000);

}


void MainWindow::OpenImage(){
    QString fileName = QFileDialog::getOpenFileName(this,tr("Load image..."),QString(),tr("Bitmap Image (*.bmp)"));
    if (fileName.isEmpty())
        return;

    if(!LoadImage(fileName)){
        QErrorMessage *error = new QErrorMessage(this);
        error->showMessage(tr("Couldn't open the image"));
        loaded=true;

    }
}

void MainWindow::SaveImageDialog(){
    QString fileName = QFileDialog::getSaveFileName(this,tr("Save image..."),QString(),tr("Images (*.bmp *.png *.jpg)"));
    if (fileName.isEmpty())
        return;

    int temp_sel = labelManager.GetSelected();
    labelManager.SetSelected(-1);
    if(!SaveImage(fileName)){
        QErrorMessage *error = new QErrorMessage(this);
        error->showMessage(tr("Couldn't save the image"));
    }
    labelManager.SetSelected(temp_sel);

    statusBar()->showMessage("Image saved",2000);
}

bool MainWindow::LoadImage(QString path){
    if(!originalImage->load(path))
        return false;

    labeledImage = new QImage(*originalImage);

    imageViewer->setPixmap(QPixmap::fromImage(*originalImage));
    ScaleImage(scaleFactor);

    width = originalImage->width();
    height = originalImage->height();

    labelManager.Clean();

    emit Loaded(true);
    statusBar()->showMessage("Image loaded",2000);
    return true;
}

bool MainWindow::SaveImage(QString path){
    if(!labeledImage->save(path))
        return false;

    return true;
}

void MainWindow::Identify(){
    proc = new ImageProcesser(originalImage);
    //imageViewer->setPixmap(QPixmap::fromImage(*(proc->GetImage())));
    IdentifyDialog *dialog = new IdentifyDialog(originalImage,this);
    if(dialog->exec()){
        threshold = dialog->GetThreshold();
        erodeSize = dialog->GetErodeSize();
        dilateSize = dialog->GetDilateSize();

        Tag();

    }
}

void MainWindow::ZoomOut(){
    ScaleImage(scaleFactor*0.8);
}

void MainWindow::ZoomIn(){
    ScaleImage(scaleFactor*1.25);
}

void MainWindow::ScaleImage(float factor){
    if(!imageViewer->pixmap())
        return;
    scaleFactor = factor;
    labelManager.SetScale(factor);
    imageViewer->resize(imageViewer->pixmap()->size()*factor);

    AdjustScrollBar(scrollArea->horizontalScrollBar(), factor);
    AdjustScrollBar(scrollArea->verticalScrollBar(), factor);

    zoomInAction->setEnabled(scaleFactor < 1.5);
    zoomOutAction->setEnabled(scaleFactor > 0.1);
}

void MainWindow::AdjustScrollBar(QScrollBar *scrollBar, double factor)
 {
     scrollBar->setValue(int(factor * scrollBar->value()
                             + ((factor - 1) * scrollBar->pageStep()/2)));
 }

void MainWindow::Tag(){

    QApplication::setOverrideCursor(Qt::WaitCursor);

    labelManager.Clean();
    *labeledImage = *originalImage;

    unsigned char **output;
    output = new unsigned char*[height];
    for (int i=0;i<height;i++){
        output[i] = new unsigned char[width];
    }
    proc->Ecualize();
    proc->Threshold(threshold);
    proc->Erode(erodeSize);
    proc->Dilate(dilateSize);
    int num = proc->TagObjects(output);


    int *xmed = new int[num];
    int *ymed = new int[num];
    int *count = new int[num];

    for(int i=0; i<num; i++){
        xmed[i]=0;
        ymed[i]=0;
        count[i]=0;
    }

    for (int i = 0; i < height; ++i){
        for (int j = 0; j < width; ++j){
            if(output[i][j]>0){
                int index=output[i][j]-1;
                count[index] +=1;
                xmed[index]+=j;
                ymed[index]+=i;
            }
        }
    }

    float med_area=0;
    float desv_tipica=0;

    for(int i=0; i<num; i++){
        med_area+=count[i];
    }
    med_area=med_area/num;

    for(int i=0; i<num; i++){
        desv_tipica+=(count[i]-med_area)*(count[i]-med_area);
    }

    desv_tipica/=num;

    desv_tipica = sqrt(desv_tipica);

    for(int i=0; i<num; i++){

        if(abs(count[i]-med_area)<2*desv_tipica){
            xmed[i]/=count[i];
            ymed[i]/=count[i];

            labelManager.AddLabel(xmed[i],ymed[i]);
        }

    }

    labelManager.PaintLabels(labeledImage);
    imageViewer->setPixmap(QPixmap::fromImage(*labeledImage));

    delete[] xmed;
    delete[] ymed;
    delete[] count;

    labeled=true;
    emit Labeled(true);

    QApplication::restoreOverrideCursor();
    QString message("Items: ");
    QString items;
    items.setNum(labelManager.GetItemNumber());
    statusBar()->showMessage(message.append(items));

}

void MainWindow::UpdateViewport(){
    *labeledImage = *originalImage;
    labelManager.PaintLabels(labeledImage);
    imageViewer->setPixmap(QPixmap::fromImage(*labeledImage));
}

void MainWindow::EnableIdentify(bool val){
    identifyAction->setEnabled(val);
}

void MainWindow::EnableSave(bool val){
    saveImageAction->setEnabled(val);
}

void MainWindow::keyPressEvent(QKeyEvent *event){
    if(event->type()==QEvent::KeyPress && event->key()==Qt::Key_Delete){
        labelManager.RemoveSelectedLabel();
    }
    else if(event->type()==QEvent::KeyPress && event->key()==Qt::Key_Plus){
        ZoomIn();
    }
    else if(event->type()==QEvent::KeyPress && event->key()==Qt::Key_Minus){
        ZoomOut();
    }
}

void MainWindow::UpdateStatusBar(){

    QString message("Items: ");
    QString items;
    items.setNum(labelManager.GetItemNumber());
    statusBar()->showMessage(message.append(items));

}

void MainWindow::OpenPreferences(){
    PreferencesDialog *dialog = new PreferencesDialog(this);
    if(dialog->exec()){
        if(labeled)
            UpdateViewport();
    }
}

void MainWindow::OpenInstructions(){
    QMessageBox::information(this,
                             "Instructions",
                             QString()+"Load an image and press Identify\n"+
                             "to set the parameters and start\n"+
                             "the chromosome labeling process.\n\n"+
                             "Once the image has been labeled\n"+
                             "the resulting labels can be edited\n"+
                             "through the following actions:\n\n"+
                             "   -Click: Select label\n"+
                             "   -Double Click: Add label\n"+
                             "   -Drag: Move label\n"+
                             "   -Delete key: Delete label\n"
                             );
}
